﻿#coding=utf-8

from ctypes import *
from my_debugger_defines import *

kernel32 = windll.kernel32

class debugger():
	def __init__(self):  #初始化
		#pass
		self.h_process = None
		self.pid = None
		self.debugger_active = False
		self.h_thread = None
		self.context = None
	
	def load(self,path_to_exe):
		#参数dwCreationFlags中的标志位控制着进程的创建方式。你若希望新创建的进程独占一个新的控制台窗口，而不是与父进程
		#共用同一个控制台，你可以加上标志位CREATE_NEW_CONSOLE creation_flags = DEBUG_PROCESS
		creation_flags  =   DEBUG_RPOCESS

		#实例化之前定义的结构体
		startupinfo     =   STARTUPINFO()
		process_information =   PROCESS_INFORMATION()

		#在以下两个成员变量的共同作用下，新建进程将在一个单独的窗体中被显示，你可以通过改变结构体STARTUPINFO中的各成员
		#变量的值来控制debugee进程的行为。
		startupinfo.dwFlags     =   0x1
		startupinfo.wShowWindow =   0x0

		#设置结构体STARTUPINFO中的成员变量
		#cb的值，用以表示结构体本身的大小
		startupinfo.cb = sizeof(startupinfo)

		if kernel32.CreateProcessA(path_to_exe,
									None,
									None,
									None,
									None,
									creation_flags,
									None,
									None,
									byref(startupinfo),
									byref(process_information)):
				
			print "[*] We have successfully lauched the process!"
			print "[*] PID: %d" % process_information.dwProcessId
            
            #保存一个指向新建进程的有效句柄,以供后续进程访问使用
			self.h_process = self.open_process(process_information.dwProcessId)
		else:    
			print "[*] Error with error code %d." % kernel32.GetLastError()
            
	def open_process(self,pid):
		#PROCESS_ALL_ACCESS对进程内存的全部操作权限
		#pid,若函数执行成功，将返回一个指向目标进程对象的句柄
		h_process = kernel32.OpenProcess(PROCESS_ALL_ACCESS,False,pid)
		return h_process
	def attach(self,pid):
		self.h_process = self.open_process(pid)
		#试图附加到目标进程，若附加失败，则输出提示后返回
		if kernel32.DebugActiveProcess(pid):
			self.debugger_active = True
			self.pid = int(pid)
			#self.run()
		else:
			print "[*] Unable to attach to the process."
	def run(self):
		# Now we have to poll the debuggee for
        # debugging events
		#现在我们就来轮询调试调试事件
		while self.debugger_active == True:
			self.get_debug_event()   
           
	def get_debug_event(self):
		debug_event = DEBUG_EVENT()
		continue_status= DBG_CONTINUE
		if kernel32.WaitForDebugEvent(byref(debug_event),INFINITE):
			self.h_thread = self.open_thread(debug_event.dwThreadID)
			self.context = self.get_thread_context(self.h_thread)
			
			print "Event Code: %d Thread ID: %d" % \
				(debug_event.dwDebugEventCode, debug_event.dwThreadID)
            # 目前我们还没有构建任何与事件处理相关的逻辑功能
            # 这里我们只是简单的恢复执行目标进程
			#raw_input("Press a key to continue...")
			#self.debugger_active = False
			kernel32.ContinueDebugEvent( \
				debug_event.dwProcessId, \
				debug_event.dwThreadID, \
				continue_status )
	def detach(self):
		if kernel32.DebugActiveProcessStop(self.pid):
			print "[*] Finished debugging. Exiting..."
			return True
		else:
			print "There was an error"
			return False 
			
	def open_thread(self, thread_id):  
		h_thread = kernel32.OpenThread(THREAD_ALL_ACCESS, None, thread_id)
		#OpenThread()获取线程句柄
		#THREAD_ALL_ACCESS取得对线程的全部操作权限
		#thread_id线程id
		
		if h_thread is not None:
			return h_thread
		else:
			print "[*] Could not obtain a valid thread handle."
			return False
	
	def enumerate_thread(self): #枚举线程
		
		thread_entry = THREADENTRY32()  #初始化结构体
		thread_list = []  #空列表
		snapshot = kernel32.CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, self.pid)
		#用CreateToolhelp32Snapshot()进行线程枚举，可以得到系统中的线程列表，返回该列表的句柄值
		#TH32CS_SNAPTHREAD(0x00000004)表示我们要取得当前系统快照对象中的所有线程信息
		
		if snapshot is not None:
			#你需要正确的设置这个结构体的大小,否则会调用失败
			thread_entry.dwSize = sizeof(thread_entry)
			success = kernel32.Thread32First(snapshot, byref(thread_entry))
			#Thread32First()获取线程列表中的第一个线程
			#第一个参数表示系统中所有线程列表的句柄值
			#第二个参数是指向结构体THREADENTRY32()的指针
			
			while success:
				if thread_entry.th32OwnerProcessID == self.pid:
				#th32OwnerProcessID表示PID,可以得知当前枚举到的线程是运行在那一个进程下
				#比较结构体中的th32OwnerProcessID与该进程的PID值来判断该线程是否属于这个进程
					thread_list.append(thread_entry.th32ThreadID)
					#th32ThreadID表示当前被枚举到的线程的TID,得到相应的线程句柄
					#若属于同一个PID，则将它的TID写入列表中
					
				success = kernel32.Thread32Next(snapshot, byref(thread_entry))
				#Thread32Next获取线程列表中的下一个线程
				
			kernel32.CloseHandle(snapshot)
			#关闭事件句柄
			return thread_list 
			#返回整个TID句柄值列表
		else:
			return False
			
	def get_thread_context (self, thread_id=None, h_thread=None ):
		
		context = CONTEXT()
		context.ContextFlags = CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS
		
		#获取线程句柄
		
		h_thread = self.open_thread(thread_id)
		if kernel32.GetThreadContext(h_thread, byref(context)):
			kernel32.CloseHandle(h_thread)
			return context
		else:
			return False
			